package com.dashboard.domain;

import java.io.Serializable;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name = "calculo_contabil")
public class CalculoContabil implements Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 6372029075021895415L;

	@Id
	@Column(name = "id_calculo_contabil")
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	
	@Column(name = "chave")
	private String chave;
	
	@Column(name = "nome", nullable = false)
	private String nome;
	
	@Column(name = "descricao")
	private String descricao;
	
	@ManyToOne
	@JoinColumn(name = "id_calculo_contabil_pai")
	private CalculoContabil calculoContabilPai;
	
	@ManyToOne
	@JoinColumn(name = "id_unidade_operacional")
	private UnidadeOperacional unidadeOperacional;
	
	@OneToMany(mappedBy = "calculoContabilPai", cascade = {CascadeType.ALL})
	private List<CalculoContabil> calculosContabeisFilhos;
	
	@ManyToOne
	@JoinColumn(name = "id_calculo_contabil_consolidado")
	private CalculoContabil calculoContabilConsolidado;
	
	@OneToMany(mappedBy = "calculoContabilConsolidado")
	private List<CalculoContabil> calculosContabeisConsolidacao;
	
	/**
	 * Valores da entidade referente ao m&ecirc;s e ano.
	 */
	@OneToMany(mappedBy = "calculoContabil")
	//@JoinColumn(name = "id_calculo_contabil", referencedColumnName = "id_calculo_contabil")
	private List<ValorCalculoContabil> valoresCalculoContabil;

	/**
	 * Construtor default.
	 */
	public CalculoContabil()
	{
		
	}
	
	/**
	 * Construtor parametrizado.
	 * 
	 * @param id - O identificador do c&aacute;lculo cont&aacute;bil
	 * @param chave - A chave do c&aacute;lculo cont&aacute;bil
	 * @param nome - O nome do c&aacute;lculo cont&aacute;bil
	 * @param descricao - A descri&ccedil;&atilde;o do c&aacute;lculo cont&aacute;bil
	 */
	public CalculoContabil(Long id, String chave, String nome, String descricao)
	{
		this.id = id;
		this.chave = chave;
		this.nome = nome;
		this.descricao = descricao;
	}

	/**
	 * @return the id
	 */
	public Long getId()
	{
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(Long id)
	{
		this.id = id;
	}

	/**
	 * @return the nome
	 */
	public String getNome()
	{
		return nome;
	}

	/**
	 * @param nome the nome to set
	 */
	public void setNome(String nome)
	{
		this.nome = nome;
	}

	/**
	 * @return the descricao
	 */
	public String getDescricao()
	{
		return descricao;
	}

	/**
	 * @param descricao the descricao to set
	 */
	public void setDescricao(String descricao)
	{
		this.descricao = descricao;
	}

	/**
	 * @return the calculoContabilPai
	 */
	public CalculoContabil getCalculoContabilPai()
	{
		return calculoContabilPai;
	}

	/**
	 * @param calculoContabilPai the calculoContabilPai to set
	 */
	public void setCalculoContabilPai(CalculoContabil calculoContabilPai)
	{
		this.calculoContabilPai = calculoContabilPai;
	}

	/**
	 * @return the calculosContabeisFilhos
	 */
	public List<CalculoContabil> getCalculosContabeisFilhos()
	{
		return calculosContabeisFilhos;
	}

	/**
	 * @param calculosContabeisFilhos the calculosContabeisFilhos to set
	 */
	public void setCalculosContabeisFilhos(
			List<CalculoContabil> calculosContabeisFilhos)
	{
		this.calculosContabeisFilhos = calculosContabeisFilhos;
	}

	/**
	 * @return the chave
	 */
	public String getChave()
	{
		return chave;
	}

	/**
	 * @param chave the chave to set
	 */
	public void setChave(String chave)
	{
		this.chave = chave;
	}

	/**
	 * @return the valoresContaContabil
	 */
	public List<ValorCalculoContabil> getValoresCalculoContabil()
	{
		return valoresCalculoContabil;
	}

	/**
	 * @param valoresCalculoContabil the valoresContaContabil to set
	 */
	public void setValoresCalculoContabil(List<ValorCalculoContabil> valoresCalculoContabil)
	{
		this.valoresCalculoContabil = valoresCalculoContabil;
	}

	/**
	 * @return the calculosContabeisConsolidacao
	 */
	public List<CalculoContabil> getCalculosContabeisConsolidacao()
	{
		return calculosContabeisConsolidacao;
	}

	/**
	 * @param calculosContabeisConsolidacao the calculosContabeisConsolidacao to set
	 */
	public void setCalculosContabeisConsolidacao(
			List<CalculoContabil> calculosContabeisConsolidacao)
	{
		this.calculosContabeisConsolidacao = calculosContabeisConsolidacao;
	}
	
	
	
	/**
	 * @return the unidadeOperacional
	 */
	public UnidadeOperacional getUnidadeOperacional()
	{
		return unidadeOperacional;
	}

	/**
	 * @param unidadeOperacional the unidadeOperacional to set
	 */
	public void setUnidadeOperacional(UnidadeOperacional unidadeOperacional)
	{
		this.unidadeOperacional = unidadeOperacional;
	}

	/**
	 * @return the calculoContabilConsolidado
	 */
	public CalculoContabil getCalculoContabilConsolidado()
	{
		return calculoContabilConsolidado;
	}

	/**
	 * @param calculoContabilConsolidado the calculoContabilConsolidado to set
	 */
	public void setCalculoContabilConsolidado(
			CalculoContabil calculoContabilConsolidado)
	{
		this.calculoContabilConsolidado = calculoContabilConsolidado;
	}

	/**
	 * @return the consolidado
	 */
	@Transient
	public boolean isConsolidado()
	{
		return getUnidadeOperacional().isConsolidado();
	}

	/**
	 * Retorna o valor do c&aacute;lculo por m&ecirc;s e ano.
	 * @param mes m&ecirc; requisitado
	 * @param ano ano requisitado
	 * 
	 * @return O Valor do c&aacute;lculo por m&ecirc;s e ano
	 */
	@Transient
	public ValorCalculoContabil getCalculo(MesEnum mes, Integer ano) 
	{
		if (getCalculosContabeisFilhos().isEmpty())
		{
			if (!isConsolidado())
			{
				ValorCalculoContabil valorCalculoContabil = null;
				
				for (ValorCalculoContabil valorCalculoContabilIteracao : valoresCalculoContabil)
				{
					if (valorCalculoContabilIteracao.getId().getMes().equals(mes) 
						&& valorCalculoContabilIteracao.getId().getAno().equals(ano))
					{
						valorCalculoContabil = valorCalculoContabilIteracao;
						break;
					}
				}
				
				/*
				 *Caso nao exista Valor cadastrado, o valor das contas deve ser zero. 
				 */
				if (valorCalculoContabil == null)
				{
					valorCalculoContabil = new ValorCalculoContabil();
					
					IdentificadorValorCalculoContabil idCalculoContabil
						= new IdentificadorValorCalculoContabil(mes, ano, this.getId());
					
					valorCalculoContabil.setId(idCalculoContabil);
					valorCalculoContabil.setValorOrcado(0.0f);
					valorCalculoContabil.setValorReal(0.0f);
				}
				
				return valorCalculoContabil;
			}
			
			ValorCalculoContabil somaValorCalculoContabil = new ValorCalculoContabil();
			somaValorCalculoContabil = new ValorCalculoContabil();
			IdentificadorValorCalculoContabil idCalculoContabil
				= new IdentificadorValorCalculoContabil(mes, ano, this.getId());
		
			somaValorCalculoContabil.setId(idCalculoContabil);
			somaValorCalculoContabil.setValorOrcado(0.0f);
			somaValorCalculoContabil.setValorReal(0.0f);
			
			for (CalculoContabil calculoContabil : calculosContabeisConsolidacao)
			{
				somaValorCalculoContabil.soma(calculoContabil.getCalculo(mes, ano));
			}
			
			return somaValorCalculoContabil;
		}
		
		//Calculo correspondente possui filhos
		List<CalculoContabil> calculosContabeis = null;
		
		if (!isConsolidado())
		{
			calculosContabeis = getCalculosContabeisFilhos();
		}
		else
		{
			calculosContabeis = calculosContabeisConsolidacao;
		}
		 
		ValorCalculoContabil somaValorCalculoContabil = new ValorCalculoContabil();
		somaValorCalculoContabil = new ValorCalculoContabil();
		IdentificadorValorCalculoContabil idCalculoContabil
			= new IdentificadorValorCalculoContabil(mes, ano, this.getId());
	
		somaValorCalculoContabil.setId(idCalculoContabil);
		somaValorCalculoContabil.setValorOrcado(0.0f);
		somaValorCalculoContabil.setValorReal(0.0f);
		
		for (CalculoContabil calculoContabil : calculosContabeis)
		{
			somaValorCalculoContabil.soma(calculoContabil.getCalculo(mes, ano));
		}
				
		return somaValorCalculoContabil;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode()
	{
		final int PRIME = 31;
		int result = 1;
		result = PRIME
				* result
				+ ((calculoContabilConsolidado == null) ? 0
						: calculoContabilConsolidado.hashCode());
		result = PRIME
				* result
				+ ((calculoContabilPai == null) ? 0 : calculoContabilPai.hashCode());
		result = PRIME
				* result
				+ ((calculosContabeisConsolidacao == null) ? 0
						: calculosContabeisConsolidacao.hashCode());
		result = PRIME
				* result
				+ ((calculosContabeisFilhos == null) ? 0
						: calculosContabeisFilhos.hashCode());
		result = PRIME * result + ((chave == null) ? 0 : chave.hashCode());
		result = PRIME * result
				+ ((descricao == null) ? 0 : descricao.hashCode());
		result = PRIME * result + ((id == null) ? 0 : id.hashCode());
		result = PRIME * result + ((nome == null) ? 0 : nome.hashCode());
		result = PRIME
				* result
				+ ((unidadeOperacional == null) ? 0 : unidadeOperacional.hashCode());
		result = PRIME
				* result
				+ ((valoresCalculoContabil == null) ? 0
						: valoresCalculoContabil.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
		{
			return true;
		}
		if (obj == null)
		{
			return false;
		}
		if (getClass() != obj.getClass())
		{
			return false;
		}
		
		CalculoContabil other = (CalculoContabil) obj;
		
		if (calculoContabilConsolidado == null)
		{
			if (other.calculoContabilConsolidado != null)
			{
				return false;
			}
		} 
		else if (!calculoContabilConsolidado.equals(other.calculoContabilConsolidado))
		{
			return false;
		}
		if (calculoContabilPai == null)
		{
			if (other.calculoContabilPai != null)
			{
				return false;
			}
		} 
		else if (!calculoContabilPai.equals(other.calculoContabilPai))
		{
			return false;
		}
		if (calculosContabeisConsolidacao == null)
		{
			if (other.calculosContabeisConsolidacao != null)
			{
				return false;
			}
		} 
		else if (!calculosContabeisConsolidacao.equals(other.calculosContabeisConsolidacao))
		{
			return false;
		}
		if (calculosContabeisFilhos == null)
		{
			if (other.calculosContabeisFilhos != null)
			{
				return false;
			}
		}
		else if (!calculosContabeisFilhos.equals(other.calculosContabeisFilhos))
		{
			return false;
		}
		if (chave == null)
		{
			if (other.chave != null)
			{
				return false;
			}
		} 
		else if (!chave.equals(other.chave))
		{
			return false;
		}
		if (descricao == null)
		{
			if (other.descricao != null)
			{
				return false;
			}
		} 
		else if (!descricao.equals(other.descricao))
		{
			return false;
		}
		if (id == null)
		{
			if (other.id != null)
			{
				return false;
			}
		} 
		else if (!id.equals(other.id))
		{
			return false;
		}
		if (nome == null)
		{
			if (other.nome != null)
			{
				return false;
			}
		} 
		else if (!nome.equals(other.nome))
		{
			return false;
		}
		if (unidadeOperacional == null)
		{
			if (other.unidadeOperacional != null)
			{
				return false;
			}
		} 
		else if (!unidadeOperacional.equals(other.unidadeOperacional))
		{
			return false;
		}
		if (valoresCalculoContabil == null)
		{
			if (other.valoresCalculoContabil != null)
			{
				return false;
			}
		} 
		else if (!valoresCalculoContabil.equals(other.valoresCalculoContabil))
		{
			return false;
		}
		
		return true;
	}	
}